using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace Oops.Xna.Framework.Graphics
{
	/// <summary>
	/// Provides methods for manipulating the directional lights used by the <see cref="PssmEffect"/> class.
	/// </summary>
	public sealed class PssmDirectionalLight
	{
		private bool enabled;

		private Vector3 position;

		private Vector3 diffuseColor;
		private Vector3 specularColor;

		private EffectParameter directionEffectParameter;
		private EffectParameter diffuseColorEffectParameter;
		private EffectParameter specularColorEffectParameter;

		public float FieldOfView = MathHelper.ToRadians(90.0f);
		public float NearPlaneDistance = 0.01f;
		public float FarPlaneDistance = 400.0f;
		internal float farPlaneMaximum = 600.0f;

		internal Matrix view = Matrix.Identity;
		internal Matrix projection = Matrix.Identity;

		/// <summary>
		/// Initializes a new instances of the <see cref="PssmDirectionalLight"/> class.
		/// </summary>
		/// <param name="direction">The <see cref="Microsoft.Xna.Framework.Graphics.EffectParameter"/> for the direction of the <see cref="PssmDirectionalLight"/>.</param>
		/// <param name="diffuseColor">The <see cref="Microsoft.Xna.Framework.Graphics.EffectParameter"/> for the diffuse color of the <see cref="PssmDirectionalLight"/>.</param>
		/// <param name="specularColor">The <see cref="Microsoft.Xna.Framework.Graphics.EffectParameter"/> for the specular color of the <see cref="PssmDirectionalLight"/>.</param>
		internal PssmDirectionalLight(
			EffectParameter direction,
			EffectParameter diffuseColor,
			EffectParameter specularColor)
		{
			// Hold onto the parameters.
			this.directionEffectParameter = direction;
			this.diffuseColorEffectParameter = diffuseColor;
			this.specularColorEffectParameter = specularColor;
		}

		internal void Copy(PssmDirectionalLight from)
		{
			this.enabled = from.enabled;
			this.diffuseColor = from.diffuseColor;
			this.specularColor = from.specularColor;

			this.diffuseColorEffectParameter.SetValue(this.diffuseColor);
			this.specularColorEffectParameter.SetValue(this.specularColor);
		}

		/// <summary>
		/// Gets or sets the <see cref="PssmDirectionalLight"/> instance's enabled state.
		/// </summary>
		public bool Enabled
		{
			get { return this.enabled; }
			set
			{
				if (this.enabled != value)
				{
					// Hold onto value.
					this.enabled = value;

					// Only set the effect parameter if the light is enabled.  Otherwise,
					// empty the effect parameters.
					if (this.enabled)
					{
						this.diffuseColorEffectParameter.SetValue(this.diffuseColor);
						this.specularColorEffectParameter.SetValue(this.specularColor);
					}
					else
					{
						this.diffuseColorEffectParameter.SetValue(Vector3.Zero);
						this.specularColorEffectParameter.SetValue(Vector3.Zero);
					}
				}
			}
		}

		public Vector3 Position
		{
			get { return this.position; }
			set
			{
				if (this.position != value)
				{
					// Hold onto the value.
					this.position = value;

					// Determine the light's view matrix.		
					this.view = Matrix.CreateLookAt(
						value,
						value + this.Direction,
						Vector3.Up);
				}
			}
		}

		/// <summary>
		/// Gets or sets the <see cref="PssmDirectionalLight"/> instance's direction.
		/// </summary>
		public Vector3 Direction
		{
			get { return this.directionEffectParameter.GetValueVector3(); }
			set
			{
				// Normalize the direction and assign it to the effect parameter.
				this.directionEffectParameter.SetValue(value);

				// Determine the light's view matrix.
				this.view = Matrix.CreateLookAt(
					this.Position,
					this.Position + value,
					Vector3.Up);
			}
		}

		/// <summary>
		/// Gets or sets the diffuse color of the <see cref="PssmDirectionalLight"/>.
		/// </summary>
		public Vector3 DiffuseColor
		{
			get { return this.diffuseColor; }
			set
			{
				// Only set the effect parameter if the light is enabled.
				if (this.enabled)
				{
					this.diffuseColorEffectParameter.SetValue(value);
				}

				// Hold onto the value internally.
				this.diffuseColor = value;
			}
		}

		/// <summary>
		/// Gets or sets the specular color of the <see cref="PssmDirectionalLight"/>.
		/// </summary>
		public Vector3 SpecularColor
		{
			get { return this.specularColor; }
			set
			{
				// Only set the effect parameter if the light is enabled.
				if (this.enabled)
				{
					this.specularColorEffectParameter.SetValue(value);
				}

				// Hold onto the value internally.
				this.specularColor = value;
			}
		}
	}

}

